/**
 * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
 *
 * Description: SLE uart sample of client. \n
 *
 * History: \n
 * 2023-04-03, Create file. \n
 */
#include "sle_one.h"
#include "securec.h"
#include "common_def.h"
#include "soc_osal.h"
#include "securec.h"
#include "product.h"
#include "bts_le_gap.h"

#include "sle_device_discovery.h"
#include "sle_connection_manager.h"
static sle_addr_t my_remote_addr = {0};
static uint16_t my_conn_id = 0;
static uint16_t my_service_start_hdl = 0;
static uint16_t my_service_end_hdl = 0;
static sle_uuid_t my_service_uuid = {0};
static uint16_t my_property_handle = 0;

static void my_seek_result_info_cbk(sle_seek_result_info_t *seek_result_data);
static void my_connect_state_changed_cbk(uint16_t conn_id, sle_acb_state_t conn_state);
static void my_find_structure_cbk(uint8_t client_id, uint16_t conn_id, ssapc_find_service_result_t *service);
static void my_find_property_cbk(uint8_t client_id, uint16_t conn_id, ssapc_find_property_result_t *property);

void my_sle_uart_client_init() {
    osal_msleep(1000); // 延时等待 SLE 初始化完毕
    osal_printk(MY_UART_CLIENT_LOG " Initializing SLE...\r\n");
    if (enable_sle() != ERRCODE_SUCC) {
        osal_printk(MY_UART_CLIENT_LOG " Failed to enable SLE!\r\n");
    }
}

void my_sle_uart_client_start() {
    my_sle_uart_client_init();

    // 注册回调函数
    sle_announce_seek_callbacks_t seek_cbk = {0};
    seek_cbk.seek_result_cb = my_seek_result_info_cbk;
    sle_announce_seek_register_callbacks(&seek_cbk);

    sle_connection_callbacks_t connect_cbk = {0};
    connect_cbk.connect_state_changed_cb = my_connect_state_changed_cbk;
    sle_connection_register_callbacks(&connect_cbk);

    ssapc_callbacks_t ssapc_cbk = {0};
    ssapc_cbk.find_structure_cb = my_find_structure_cbk;
    ssapc_cbk.ssapc_find_property_cbk = my_find_property_cbk;
    ssapc_register_callbacks(&ssapc_cbk);

    // 开始扫描
    my_start_scan();
}

void my_sle_uart_client_write(uint8_t *data, uint16_t length) {
    if (my_property_handle == 0) {
        osal_printk(MY_UART_CLIENT_LOG " Property handle not found\r\n");
        return;
    }

    ssapc_write_param_t write_param = {0};
    write_param.handle = my_property_handle;
    write_param.type = SSAP_PROPERTY_TYPE_VALUE;
    write_param.data = data;
    write_param.data_len = length;

    ssapc_write_req(0, my_conn_id, &write_param);
}

void my_sle_uart_client_close() {
    if (my_conn_id != 0) {
        sle_disconnect_device(my_conn_id);
        my_conn_id = 0;
    }
}

void my_start_scan() {
    sle_seek_param_t param = {0};
    param.own_addr_type = 0;
    param.filter_duplicates = 0;
    param.seek_filter_policy = 0;
    param.seek_phys = 1;
    param.seek_type[0] = 1;
    param.seek_interval[0] = 100; // 设置合适的扫描间隔
    param.seek_window[0] = 100;   // 设置合适的扫描窗口

    sle_set_seek_param(&param);
    sle_start_seek();
}

static void my_seek_result_info_cbk(sle_seek_result_info_t *seek_result_data) {
    if (seek_result_data != NULL && strstr((const char *)seek_result_data->data, MY_SLE_UART_SERVER_NAME) != NULL) {
        osal_printk(MY_UART_CLIENT_LOG " Found target device, connecting...\r\n");
        memcpy(&my_remote_addr, &seek_result_data->addr, sizeof(sle_addr_t));
        sle_stop_seek();
        sle_connect_remote_device(&my_remote_addr);
    }
}

static void my_connect_state_changed_cbk(uint16_t conn_id, sle_acb_state_t conn_state) {
    if (conn_state == SLE_ACB_STATE_CONNECTED) {
        osal_printk(MY_UART_CLIENT_LOG " Connected to device\r\n");
        my_conn_id = conn_id;
        ssap_exchange_info_t info = {0};
        info.mtu_size = MY_SLE_MTU_SIZE_DEFAULT;
        info.version = 1;
        ssapc_exchange_info_req(0, my_conn_id, &info);
    } else if (conn_state == SLE_ACB_STATE_DISCONNECTED) {
        osal_printk(MY_UART_CLIENT_LOG " Disconnected from device\r\n");
        my_conn_id = 0;
        my_start_scan();
    }
}

static void my_find_structure_cbk(uint8_t client_id, uint16_t conn_id, ssapc_find_service_result_t *service) {
    osal_printk(MY_UART_CLIENT_LOG " Found service: start_hdl=0x%02x, end_hdl=0x%02x, uuid_len=%d\r\n",
                service->start_hdl, service->end_hdl, service->uuid.len);
    my_service_start_hdl = service->start_hdl;
    my_service_end_hdl = service->end_hdl;
    memcpy(&my_service_uuid, &service->uuid, sizeof(sle_uuid_t));

    ssapc_find_structure_param_t find_param = {0};
    find_param.type = SSAP_FIND_TYPE_PROPERTY;
    find_param.start_hdl = my_service_start_hdl;
    find_param.end_hdl = my_service_end_hdl;
    ssapc_find_structure(0, conn_id, &find_param);
}

static void my_find_property_cbk(uint8_t client_id, uint16_t conn_id, ssapc_find_property_result_t *property) {
    osal_printk(MY_UART_CLIENT_LOG " Found property: handle=%d\r\n", property->handle);
    my_property_handle = property->handle;
}
